package asteroids.model;

import asteroids.Util;
import be.kuleuven.cs.som.annotate.*;
import asteroids.model.Status;

/**
 * A class representing an object moving in space.
 * 
 * @invar Every space object has a nonzero position.
 * 			| getPosition() != null
 * @invar Each space object has a nonzero speed.
 * 			| getSpeed() != null
 * @invar A space object's speed will never exceed the speed of light c.
 * 			| getSpeed().getTotalSpeed() <= c
 * @invar The radius must be valid and greater than zero for each space object. 
 * 			| isValidRadius(getRadius(), 0)
 * @invar The mass must be valid for every space object. 
 * 			| isValidMass(getMass())
 * @invar The minimum radius must be valid for every space object. 
 * 			| Util.isValidDouble(min_radius)
 * @invar Each space object has a nonzero status. 
 * 			| getStatus() != null
 * @author Martin & Anton
 * 
 */
public class SpaceObject {

	// variables and constants
	private Vector position;
	private Speed speed;
	private World world;

	protected static final double c = 300000;

	private final double radius;
	private final double mass;

	private Status status;

	// constructors

	/**
	 * Creates a SpaceObject with the given coordinates, the given speed, given
	 * radius, and given angle if these are all valid specified by their
	 * respective isValid methods.
	 * 
	 * @param x
	 * @param y
	 * @param speed_x
	 * @param speed_y
	 * @param radius
	 * @param mass
	 * @param min_radius
	 * @param max_speed
	 * @post The coordinates, speed, angle and radius will be initialized in
	 *       this method. | (new this).radius = radius && (new this).position =
	 *       new Vector(x,y) | && (new this).speed = new Speed(speed_x, speed_y)
	 *       && (new this).angle = angle
	 * @throws IllegalArgumentException
	 *             If the radius is not valid specified by isValidRadius, or if
	 *             the mass is not valid specified by isValidMass, or the
	 *             coordinates are not valid, specified by Util.isValidDouble,
	 *             or if the speed is not valid specified by isValidSpeed. |
	 *             !isValidRadius(radius) || !Vector.Util.isValidDouble(x) | ||
	 *             !Vector.Util.isValidDouble(y) || !Speed.isValidSpeed(speed_x,
	 *             speed_y)
	 */
	public SpaceObject(double x, double y, double speed_x, double speed_y,
			double radius, double mass, double min_radius, double max_speed)
			throws IllegalArgumentException {
		if (!Util.isValidDouble(x) || !Util.isValidDouble(y))
			throw new IllegalArgumentException();
		if (!Util.isValidDouble(max_speed) || max_speed > c)
			throw new IllegalArgumentException();
		if (!Speed.isValidSpeed(speed_x, speed_y, max_speed))
			throw new IllegalArgumentException();
		if (!Util.isValidDouble(min_radius))
			throw new IllegalArgumentException();
		if (!isValidRadius(radius, min_radius))
			throw new IllegalArgumentException();
		if (!isValidMass(mass))
			throw new IllegalArgumentException();
		this.radius = radius;
		this.mass = mass;
		this.position = new Vector(x, y);
		this.speed = new Speed(speed_x, speed_y, max_speed);
		this.world = null;
		this.status = Status.ALIVE;
	}

	// getters and setters
	@Basic
	public double getX() {
		return position.getX();
	}

	@Basic
	public double getY() {
		return position.getY();
	}

	@Basic
	public Vector getPosition() {
		return position;
	}

	@Basic
	public double getXVelocity() {
		return speed.getX();
	}

	@Basic
	public double getYVelocity() {
		return speed.getY();
	}

	@Basic
	public Speed getSpeed() {
		return speed;
	}

	@Basic @Immutable
	public double getRadius() {
		return radius;
	}

	@Basic @Immutable
	public double getMass() {
		return mass;
	}

	@Basic
	public World getWorld() {
		return this.world;
	}

	@Basic
	protected Status getStatus() {
		return status;
	}

	/**
	 * 
	 * @param x
	 * @param y
	 * @post Sets the position of this SpaceObject to the given position. | (new
	 *       this).getX() == x | (new this).getY() == y
	 * @throws IllegalArgumentException
	 *             If the given position is not valid. | !(Util.isValidDouble(x)
	 *             && Util.isValidDouble(y))
	 */
	public void setPosition(double x, double y) throws IllegalArgumentException {
		this.position.setSpeed(x, y);
	}

	/**
	 * Set x velocity
	 * @param speed_x
	 * @effect speed.setX(speed_x)
	 * 			If the ship is alive
	 * 			| if(isAlive())
	 */
	@Raw
	public void setXVelocity(double speed_x) {
		if(isAlive())
			this.speed.setX(speed_x);
	}

	/**
	 * Set y velocity
	 * @param speed_y
	 * @effect speed.setY(speed_y)
	 * 			If the ship is alive
	 * 			| if(isAlive())
	 */
	@Raw
	public void setYVelocity(double speed_y) {
		if(isAlive())
			this.speed.setY(speed_y);
	}

	/**
	 * Set velocity.
	 * @param speed_x
	 * @param speed_y
	 * @effect If the given speeds are valid, this method will use the 2 basic
	 *         velocity setters. If the ship is alive
	 *         | speed.setCoord(speed_x, speed_y)
	 * 		   | if(isAlive())
	 * 
	 */
	@Raw
	public void setVelocity(double speed_x, double speed_y) {
		if(isAlive())
			this.speed.setSpeed(speed_x, speed_y);
	}

	/**
	 * 
	 * @param world
	 * @throws NullPointerException
	 *             If the given world is null, then a NullPointerExcpetion is
	 *             thrown. | if(world == null)
	 * @post The world will be set as the given world. 
	 * 			| (new this).getWorld() == world;
	 * @throws IllegalStateException
	 * 			If the object is not alive
	 * 			| if(!isAlive())
	 */
	public void setWorld(World world) throws NullPointerException , IllegalStateException{
		if (!isAlive())
			throw new IllegalStateException();
		if (world == null)
			throw new NullPointerException();
		if (getWorld() == null)
			this.world = world;
	}

	/**
	 * Sets the world as null.
	 * 
	 * @post The world will be null 
	 * 		| (new this).getWorld() == null
	 */
	protected void setWorldNull() {
		if (getWorld() != null)
			this.world = null;
	}

	/**
	 * Sets the status as the given status.
	 * 
	 * @param status
	 * @post The status will be the given status. 
	 * 		| (new this).getStatus() == status
	 */
	protected void setStatus(Status status) {
		this.status = status;
	}

	// checkers

	/**
	 * 
	 * @param radius
	 * @return Returns true if the radius is smaller than the previously
	 *         specified mininum radius, else will return false.
	 *         | return == Util.isValidDouble(input)
	 *		   | && Util.fuzzyMoreThanOrEqualTo(input, min_radius))
	 */
	protected static boolean isValidRadius(double input, double min_radius) {
		if (Util.isValidDouble(input)
				&& Util.fuzzyMoreThanOrEqualTo(input, min_radius)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 
	 * @param input
	 * @return true if the input value is a valid mass. | result ==
	 *         (Util.isValidDouble(input) && input >= 0)
	 */
	protected static boolean isValidMass(double input) {
		if (Util.isValidDouble(input) && Util.fuzzyMoreThanOrEqualTo(input, 0)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Checks if the status is alive.
	 * 
	 * @return getStatus() == Status.ALIVE
	 */
	public boolean isAlive() {
		return getStatus() == Status.ALIVE;
	}

	/**
	 * Moves the space object, based on its speed and the given time.
	 * @param time
	 * @post The SpaceObject will have moved, with the velocity times the given
	 *       time, from his original position. 
	 *       | (new this).getX() == this.getX() + time * this.getXVelocity() 
	 *       |		&& (new this).getY() == this.getY() + time * this.getYVelocity()
	 * @throws IllegalArgumentException
	 *         If the given time is negative, infinite or not a number. 
	 *         |((time<0) || Double.isInfinite(time) || Double.isNaN(time))
	 * @throws IllegalArgumentException
	 *         If the resulting position is not valid.
	 * @throws IllegalStateException
	 * 			If the object is not alive
	 * 			| if(!isAlive())
	 */
	public void move(double time) throws IllegalArgumentException, IllegalStateException {
		if (!isAlive())
			throw new IllegalStateException();
		if (!Util.isValidDouble(time) || Util.fuzzyLessThan(time, 0)) {
			throw new IllegalArgumentException("time is " + time);
		} else {
			setPosition(getX() + time * getXVelocity(), getY() + time
					* getYVelocity());
		}
	}

	/**
	 * 
	 * @param time
	 * @return The returned result is the position after moving during the given
	 *         time. 
	 *         | result = Vector(this.getX() + time*this.getXVelocity(), 
	 *         | this.getY() + time*this.getYVelocity())
	 * @throws IllegalArgumentException
	 *         If the given time is negative, infinite or not a number. 
	 *         | ((time<0) || Double.isInfinite(time) || Double.isNaN(time))
	 * @throws IllegalArgumentException
	 *         If the resulting position is not valid.
	 * @throws IllegalStateException
	 * 			If the object is not alive
	 * 			| if(!isAlive())
	 */
	public Vector getPositionAfter(double time) throws IllegalArgumentException, IllegalStateException {
		if (!isAlive())
			throw new IllegalStateException();
		if(!Util.isValidDouble(time)|| Util.fuzzyLessThan(time,  0)) {
			throw new IllegalArgumentException("" + time);
		} else {
			return new Vector(this.getX() + time * this.getXVelocity(),
					this.getY() + time * this.getYVelocity());
		}
	}

	/**
	 * Get the distance to a given object in a given time.
	 * 
	 * @param object
	 * @param time
	 * @return return === this.getPositionAfter(time).getDistanceTo(object.getPositionAfter(time))
	 * 		   | - this.getRadius() - object.getRadius()
	 * @throws NullPointerException
	 *         When a null object has been given. 
	 *         | object == null
	 * @throws IllegalArgumentException
	 *         When a negative time has been given. 
	 *         | time < 0.0
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public double getDistanceTo(SpaceObject object, double time)
			throws NullPointerException, IllegalArgumentException, IllegalStateException {
		if(object == null)
			throw new NullPointerException();
		if (this == object) {
			return 0;
		}
		if (time < 0.0)
			throw new IllegalArgumentException();
		if (!isAlive() || !object.isAlive())
			throw new IllegalStateException();
		double dis = this.getPositionAfter(time).getDistanceTo(
		object.getPositionAfter(time));
		return dis - this.getRadius() - object.getRadius();
		}

	/**
	 * Get the distance between this object and another (= the distance one
	 * object has to move, before touching the other).
	 * 
	 * @param object
	 * @return result == this.distanceBetween(other,0.0)
	 * @throws NullPointerException
	 *        When a null object has been given. 
	 *        | object == null
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public double getDistanceTo(SpaceObject object) throws NullPointerException, IllegalStateException {
		if(object == null)
			throw new NullPointerException();
		if (!isAlive() || !object.isAlive())
			throw new IllegalStateException();
		return getDistanceTo(object, 0.0);
	}

	/**
	 * Return the time it will take for this spaceObject to collide with the
	 * given spaceObject.
	 * 
	 * @param object
	 * @return The resulting time is not negative and different from Double.NaN
	 *         | Util.fuzzyMoreThanOrEqualTo(result, 0) &&
	 *         (!Double.isNaN(result))
	 * @result If the resulting time is finite, the distance between both
	 *         objects is fuzzy equal to zero if they would both move during the
	 *         resulting time. 
	 *         | if(result < Double.POSITIVE_INFINITY) then 
	 *         | Util.fuzzyEquals(this.getDistanceTo(object, result), 0.0)
	 * @result If the resulting time is finite, both objects will not have a
	 *         distance fuzzy equal to zero if they move during a time less than
	 *         the result. 
	 *         | if(result < Double.POSITIVE_INFINITY) then 
	 *         | for each time in (0...result): 
	 *         | !Util.fuzzyEquals(this.getDistanceTo(object, time), 0.0)
	 * @result If the resulting time is infinite, the distance between both
	 *         objects will never be fuzzy equal to zero for every possible
	 *         finite time they would move. 
	 *         | if(result == Double.POSITIVE_INFINITY) then 
	 *         | for each time in (0...Double.POSITIVE_INFINITY): 
	 *         | !Util.fuzzyEquals(this.getDistanceTo(object, time), 0.0)
	 * @throws NullPointerException
	 *         When a null object has been given. 
	 *         | object == null
	 * @throws IllegalStateException
	 * 			If this object or the given object is not alive.
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public double getTimeToCollision(SpaceObject object)
			throws NullPointerException, IllegalStateException {
		if(object == null)
			throw new NullPointerException();
		if (!isAlive() || !object.isAlive())
			throw new IllegalStateException();
		double deltaRX = object.getX() - this.getX();
		double deltaRY = object.getY() - this.getY();
		double deltaVX = object.getXVelocity() - this.getXVelocity();
		double deltaVY = object.getYVelocity() - this.getYVelocity();
		double sigma = object.getRadius() + this.getRadius();

		double VR = deltaVX * deltaRX + deltaVY * deltaRY;
		double VV = Math.pow(deltaVX, 2) + Math.pow(deltaVY, 2);
		double RR = Math.pow(deltaRX, 2) + Math.pow(deltaRY, 2);

		double d = Math.pow(VR, 2) - VV * (RR - Math.pow(sigma, 2));

		if (Util.fuzzyMoreThanOrEqualTo(VR, 0))
			return Double.POSITIVE_INFINITY;
		if (Util.fuzzyLessThanOrEqualTo(d, 0)) {
			return Double.POSITIVE_INFINITY;
		} else {
			double result = -(VR + Math.sqrt(d)) / VV;
			return result;
		}
	}
	
	/**
	 * Return the time it will take for this space object to collide with a boundary.
	 * @return The resulting time is not negative and different from Double.NaN
	 * 			| Util.fuzzyMoreThanOrEqualTo(result, 0) && (!Double.isNaN(result))
	 * @result If the resulting time is finite, the distance between this object and one of the boundaries
	 * 			is fuzzy equal to zero if this object would move during the resulting time. 
	 * 			| if(result < Double.POSITIVE_INFINITY) then
	 * 			|  		Util.fuzzyEquals(this.getPositionAfter(time).getX()+getRadius(), getWorld().getWidth()) ||
	 * 			|  		Util.fuzzyEquals(this.getPositionAfter(time).getX()-getRadius(), 0) ||
	 * 			|  		Util.fuzzyEquals(this.getPositionAfter(time).getY()+getRadius(), getWorld().getHeight()) ||
	 * 			|  		Util.fuzzyEquals(this.getPositionAfter(time).getY()-getRadius(), 0) 
	 * @result If the resulting time is finite, the distance between this object and one of the boundaries
	 * 			will not be zero if this object moves during a time less than the result.
	 * 			| if(result < Double.POSITIVE_INFINITY) then
	 * 			|	for each time in (0...result):
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getX()+getRadius(), getWorld().getWidth()) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getX()-getRadius(), 0) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getY()+getRadius(), getWorld().getHeight()) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getY()-getRadius(), 0) 
	 * @result If the resulting time is infinite, the distance between this and the boundaries will never be
	 * 			fuzzy equal to zero for every possible finite time this object would move.
	 * 			| if(result == Double.POSITIVE_INFINITY) then
	 * 			|	for each time in (0...Double.POSITIVE_INFINITY):
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getX()+getRadius(), getWorld().getWidth()) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getX()-getRadius(), 0) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getY()+getRadius(), getWorld().getHeight()) 
	 * 			|  		! Util.fuzzyEquals(this.getPositionAfter(time).getY()-getRadius(), 0) 
	 * @throws IllegalStateException
	 * 			When this object is not located in a world, an thus can't collide with a boundary.
	 * 			| getWorld() == null
	 * @throws IllegalStateException
	 * 			If this object is not alive
	 * 			| if(!isAlive())
	 */
	public double getTimeToBoundaryCollision() throws IllegalStateException{
		if (!isAlive())
			throw new IllegalStateException();
		if(getWorld() == null)
			throw new IllegalStateException();
		double xBoundary;
		double yBoundary;
		if (getXVelocity() > 0)
			xBoundary = (getWorld().getWidth() - getX() - getRadius())
					/ getXVelocity();
		else if (getXVelocity() < 0)
			xBoundary = Math.abs((getX() - getRadius()) / getXVelocity());
		else
			xBoundary = Double.POSITIVE_INFINITY;

		if (getYVelocity() > 0)
			yBoundary = (getWorld().getHeight() - getY() - getRadius())
					/ getYVelocity();
		else if (getYVelocity() < 0)
			yBoundary = Math.abs((getY() - getRadius()) / getYVelocity());
		else
			yBoundary = Double.POSITIVE_INFINITY;
		return Math.min(xBoundary, yBoundary);
	}

	/**
	 * Get the collision position with the given object. [xPos,yPos].
	 * @param object
	 * @return	Returns null if this object will never collide with one of the boundaries.
	 * 			| if(Double.isInfinite(this.getTimeToBoundaryCollision())
	 * 			|	return == null
	 * @return	The position of the first collision between this object and one of the boundaries.
	 * 			| Let position == this.getPositionAfter(time)
	 * 			| Let xLeft = position.getX()		let xRight = getWorld().getWidth() - position.getX()
	 * 			| Let yDown = position.getY()		let yUp    = getWorld().getHeight()- position.getY()
	 * 			| Let min = Math.min(Math.min(xLeft, xRight), Math.min(yDown, yUp))
	 * 			| if(Util.fuzzyEquals(min,xLeft))
	 * 			|	position[0] == 0								position[1] == position.getY()
	 * 			| if(Util.fuzzyEquals(min,xRight))
	 * 			|	position[0] == position.getX() + getRadius()	position[1] == position.getY()
	 * 			| if(Util.fuzzyEquals(min,yDown))
	 * 			|	position[0] == position.getX()					position[1] == 0
	 * 			| if(Util.fuzzyEquals(min,yUp))
	 * 			|	position[0] == position.getX()					position[1] == position.getY() + getRadius()
	 * @throws IllegalStateException
	 * 			When this object is not located in a world, an thus can't collide with a boundary.
	 * 			| getWorld() == null
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public double[] getBoundaryCollisionPosition() throws IllegalStateException{
		if(!isAlive())
			throw new IllegalStateException();
		if(getWorld() == null)
			throw new IllegalStateException();
		double time = this.getTimeToBoundaryCollision();
		if(Double.isInfinite(time))
			return null;
		double [] position = new double[2];
		double positionX = this.getPositionAfter(time).getX();
		double positionY = this.getPositionAfter(time).getY();
		double xLeft = positionX; double xRight = getWorld().getWidth() - positionX;
		double yDown = positionY; double yUp = getWorld().getHeight() - positionY;
		double min = Math.min(Math.min(xLeft, xRight), Math.min(yDown, yUp));
		if(Util.fuzzyEquals(min, xLeft)){
			position[0] = 0;
			position[1] = positionY;
		}
		else if(Util.fuzzyEquals(min, xRight)){
			position[0] = positionX + getRadius();
			position[1] = positionY;
		}
		else if(Util.fuzzyEquals(min, yDown)){
			position[0] = positionX;
			position[1] = 0;
		}
		else if(Util.fuzzyEquals(min, yUp)){
			position[0] = positionX;
			position[1] = positionY + getRadius();
		}
		return position;
	}
	
	/**
	 * Get the collision position with the given object. [xPos,yPos].
	 * @param object
	 * @return Returns null if the object and this object will never collide. 
	 *  	    |if(Double.isInfinite(this.getTimeToCollision(object)) 
	 *          | return == null
	 * @return The position of the first collision of the given object with this
	 *         object. | Let time == this.getTimeToCollision(object) 
	 *         | Let radiusPart == this.getRadius()/(this.getRadius() + object.getRadius()) 
	 *         | Let thisPosition == this.getPositionAfter(time) 
	 *         | Let otherPosition == object.getPositionAfter(time) 
	 *         | return[0] == thisPosition.getX() + radiusPart*(otherPosition.getX() - thisPosition.getX()) 
	 *         | return[1] == thisPosition.getY() + radiusPart*(otherPosition.getY() - thisPosition.getY())
	 * @throws NullPointerException
	 *         If the given object is null 
	 *         | if(object == null)
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public double[] getCollisionPosition(SpaceObject object) throws NullPointerException, IllegalStateException {
		if (object == null)
			throw new NullPointerException();
		if (!isAlive() || !object.isAlive())
			throw new IllegalStateException();
		
		double time = this.getTimeToCollision(object);
		if (Double.isInfinite(time)) {
			return null;
		}
		if(Util.fuzzyEquals(time,  0))
			time = 0;
		double[] position = new double[2];
		double radiusPart = this.getRadius()
				/ (this.getRadius() + object.getRadius());
		double positionX = this.getPositionAfter(time).getX();
		double positionY = this.getPositionAfter(time).getY();
		position[0] = positionX + radiusPart
				* ((object.getPositionAfter(time).getX()) - positionX);
		position[1] = positionY + radiusPart
				* ((object.getPositionAfter(time).getY()) - positionY);
		return position;
	}

	/**
	 * Returns if the this object overlaps with a given object.
	 * 
	 * @param object
	 * @return true 
	 *         If the two objects are the same. 
	 *         | return == (this == object)
	 * @return true 
	 *         If the two objects overlap. 
	 *         | return == (this.getDistanceTo(object) < 0)
	 * @throws NullPointerException
	 *         When a null object has been given. 
	 *         | object == null
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public boolean overlapsWith(SpaceObject object) throws NullPointerException, IllegalStateException{
		if(!isAlive() || !object.isAlive())
			throw new IllegalStateException();
		if (this == object)
			return true;
		else {
			return (getDistanceTo(object) < 0);
		}
	}

	/**
	 * Sets the world to null, and sets its status to dead.
	 * 
	 * @post   Status is set to DEAD. 
	 *         | (new this).getStatus == Status.DEAD
	 * @effect setWorldNull() If status is not DEAD already, the world will be
	 *         set as null 
	 *         | If(isAlive()) 
	 *         | Then this.setWorldNull()
	 */
	public void die() {
		if (isAlive()) {
			this.status = Status.DEAD;
			this.setWorldNull();
		}
	}

	/**
	 * This method lets this object and the given object bounce with eachother.
	 * They will change velocity depending on current speed, mass, and radius.
	 * 
	 * @param object
	 * @post
	 * @throws NullPointerException
	 *         If the given object is null 
	 *         | if(object == null)
	 * @throws IllegalStateException
	 * 			If this object is not alive
	 * 			| if(!isAlive())
	 */
	public void bounce(SpaceObject object) throws NullPointerException, IllegalStateException {
		if (!isAlive())
			throw new IllegalStateException();
		if (object == null)
			throw new NullPointerException();

		double vx1 = this.getXVelocity();
		double rx1 = this.getX();
		double vy1 = this.getYVelocity();
		double ry1 = this.getY();
		double vx2 = object.getXVelocity();
		double rx2 = object.getX();
		double vy2 = object.getYVelocity();
		double ry2 = object.getY();

		double m1 = this.getMass();
		double m2 = object.getMass();
		double sigma = object.getRadius() + this.getRadius();

		double deltaVR = (vx2 - vx1) * (rx2 - rx1) + (vy2 - vy1) * (ry2 - ry1);
		double J = 2 * m1 * m2 * deltaVR / (sigma * (m1 + m2));
		double Jx = J * (rx2 - rx1) / sigma;
		double Jy = J * (ry2 - ry1) / sigma;

		object.setVelocity(vx2 - Jx / m2, vy2 - Jy / m2);
		setVelocity(vx1 + Jx / m1, vy1 + Jy / m1);
	}

	/**
	 * This method will
	 * @post The axis where this collided against, that velocity will be
	 *       reversed. 
	 *       | if(Util.fuzzyEquals(getX()+getRadius(), world.getWidth()) || Util.fuzzyEquals(getX()-getRadius() ,0)) 
	 *       |then (new this).getXVelocity() == this.getYVelocity()*-1 
	 *       |if(Util.fuzzyEquals(getY()+getRadius(), world.getHeight()) || Util.fuzzyEquals(getY()-getRadius() ,0)) 
	 *       | then (new this).getYVelocity() == this.getYVelocity()*-1
	 * @throws IllegalStateException
	 * 			If this object is not alive or the given object
	 * 			| if(!isAlive() || !object.isAlive())
	 */
	public void bounceWall() throws IllegalStateException {
		if (!isAlive())
			throw new IllegalStateException();
		if(Util.fuzzyEquals(getX() + getRadius(), getWorld().getWidth())
					|| Util.fuzzyEquals(getX() - getRadius(), 0))
				setXVelocity(getXVelocity() * -1);
		if (Util.fuzzyEquals(getY() + getRadius(), getWorld().getHeight())
					|| Util.fuzzyEquals(getY() - getRadius(), 0))
				setYVelocity(getYVelocity() * -1);
	}
}


